/**
 * 
 */
package org.yelongframework.model.support.mybatis.sql.executor;

import java.sql.Connection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.ibatis.session.SqlSession;
import org.yelongframework.commons.util.ListUtil;
import org.yelongframework.core.sql.param.SqlParam;
import org.yelongframework.core.sql.param.SqlParamEntry;
import org.yelongframework.core.sql.result.CallSqlResult;
import org.yelongframework.model.support.mybatis.mapper.GenericMapperParamBuilder;
import org.yelongframework.model.support.mybatis.sql.MybatisParamMap;
import org.yelongframework.mybatis.mapper.GenericMapper;
import org.yelongframework.mybatis.mapper.GenericMapperParam;
import org.yelongframework.sql.SqlRuntimeException;
import org.yelongframework.sql.executor.AbstractSqlExecutor;
import org.yelongframework.sql.executor.SqlExecuteException;
import org.yelongframework.util.Assert;

/**
 * mybatis实现的SQL执行器的抽象实现
 * 
 * @since 1.0.0
 */
public abstract class AbstractMybatisSqlExecutor extends AbstractSqlExecutor implements MybatisSqlExecutor {

	private final GenericMapperParamBuilder genericMapperParamBuilder;

	// ==================================================constructor==================================================

	public AbstractMybatisSqlExecutor(GenericMapperParamBuilder genericMapperParamBuilder) {
		Assert.notNull(genericMapperParamBuilder, "genericMapperParamBuilder cannot be null");
		this.genericMapperParamBuilder = genericMapperParamBuilder;
	}

	// ==================================================sqlExecutorImpl==================================================

	@Override
	public Integer executeUpdate(String sql, Object... params) throws SqlRuntimeException {
		return getGenericMapper().executeUpdate(genericMapperParamBuilder.build(sql, params));
	}

	@Override
	public List<Map<String, Object>> executeQuery(String sql, Object... params) throws SqlRuntimeException {
		return getGenericMapper().executeQuery(genericMapperParamBuilder.build(sql, params));
	}

	@Override
	public <T> List<T> executeQueryColumn(String sql, Object... params) throws SqlRuntimeException {
		return getGenericMapper().executeQueryColumn(genericMapperParamBuilder.build(sql, params));
	}

	@Override
	public CallSqlResult executeCall(String sql, SqlParam sqlParam) throws SqlRuntimeException {
		// 构建参数
		GenericMapperParam genericMapperParam = genericMapperParamBuilder.build(sql, sqlParam);
		// 执行
		getGenericMapper().executeCall(genericMapperParam);
		// 构建结果
		Map<Integer, Object> parameterIndexValueMap = new LinkedHashMap<>();
		// 所有存在输出的参数
		Map<Integer, SqlParamEntry> parameterIndexMapModeContainOut = sqlParam.getParameterIndexMapModeContainOut();
		for (Entry<Integer, SqlParamEntry> entry : parameterIndexMapModeContainOut.entrySet()) {
			Integer paramIndex = entry.getKey();
			String paramName = genericMapperParam.getParamNameByParamIndex(paramIndex);
			parameterIndexValueMap.put(paramIndex, genericMapperParam.get(paramName));
		}
		CallSqlResult callSqlResult = new CallSqlResult(parameterIndexValueMap);
		return callSqlResult;
	}

	@Override
	public Connection getConnection() {
		try {
			return getSqlSession().getConfiguration().getEnvironment().getDataSource().getConnection();
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	// ==================================================mybatisSqlExecutorImpl==================================================

	@Override
	public Integer executeUpdate(String sql, MybatisParamMap mybatisParamMap) {
		return getGenericMapper().executeUpdate(genericMapperParamBuilder.build(sql, mybatisParamMap));
	}

	@Override
	public List<Map<String, Object>> executeQuery(String sql, MybatisParamMap mybatisParamMap) {
		return getGenericMapper().executeQuery(genericMapperParamBuilder.build(sql, mybatisParamMap));
	}

	@Override
	public Map<String, Object> executeQueryRow(String sql, MybatisParamMap mybatisParamMap) {
		return ListUtil.get(executeQuery(sql, mybatisParamMap), 0);
	}

	@Override
	public <T> List<T> executeQueryColumn(String sql, MybatisParamMap mybatisParamMap) {
		return getGenericMapper().executeQueryColumn(genericMapperParamBuilder.build(sql, mybatisParamMap));
	}

	@Override
	public <T> T executeQuerySingleObject(String sql, MybatisParamMap mybatisParamMap) {
		return ListUtil.get(executeQuerySingleObject(sql, mybatisParamMap), 0);
	}

	@Override
	public Long executeQueryCount(String sql, MybatisParamMap mybatisParamMap) {
		Object result = executeQuerySingleObject(sql, mybatisParamMap);
		if (null == result) {
			return null;
		}
		if (result instanceof Number) {
			return ((Number) result).longValue();
		} else {
			throw new SqlExecuteException("无法转换" + result + "为Long类型数据");
		}
	}

	// ==================================================通用映射器==================================================

	@Override
	public synchronized GenericMapper getGenericMapper() {
		SqlSession sqlSession = getSqlSession();
		try {
			return sqlSession.getMapper(GenericMapper.class);
		} catch (Exception e) {
			sqlSession.getConfiguration().addMapper(GenericMapper.class);
			return getSqlSession().getMapper(GenericMapper.class);
		}
	}

	@Override
	public GenericMapperParamBuilder getGenericMapperParamBuilder() {
		return genericMapperParamBuilder;
	}

}
